#pragma once

#include "Channel.hpp"
#include "EventLoop.hpp"
#include "Logger.hpp"
#include <hiredis/async.h>
#include <hiredis/hiredis.h>
#include <hiredis/read.h>
#include <iostream>

using namespace zephyr;

static void addRead(void *);
static void delRead(void *);
static void addWrite(void *);
static void delWrite(void *);
static void cleanup(void *);

class RedisMuduoAdapter {
public:
  void redisMuduoHandleRead() { redisAsyncHandleRead(this->m_ctx); }

  void redisMuduoHandleWrite() { redisAsyncHandleWrite(this->m_ctx); }

  friend void addRead(void *privdata) {
    RedisMuduoAdapter *adapter = static_cast<RedisMuduoAdapter *>(privdata);
    if (adapter->m_channel) {
      adapter->m_channel->setReadCallback(
          std::bind(&RedisMuduoAdapter::redisMuduoHandleRead, adapter));
      adapter->m_channel->enableReading();
    }
  }
  friend void delRead(void *privdata) {
    RedisMuduoAdapter *adapter = static_cast<RedisMuduoAdapter *>(privdata);
    if (adapter->m_channel) {
      adapter->m_channel->setReadCallback(
          std::bind(&RedisMuduoAdapter::redisMuduoHandleRead, adapter));
      adapter->m_channel->disableReading();
    }
  }
  friend void addWrite(void *privdata) {
    RedisMuduoAdapter *adapter = static_cast<RedisMuduoAdapter *>(privdata);
    if (adapter->m_channel) {
      adapter->m_channel->setWriteCallback(
          std::bind(&RedisMuduoAdapter::redisMuduoHandleWrite, adapter));
      adapter->m_channel->enableWriting();
    }
  }
  friend void delWrite(void *privdata) {
    RedisMuduoAdapter *adapter = static_cast<RedisMuduoAdapter *>(privdata);
    if (adapter->m_channel) {
      adapter->m_channel->setWriteCallback(
          std::bind(&RedisMuduoAdapter::redisMuduoHandleWrite, adapter));
      adapter->m_channel->disableWriting();
    }
  }
  friend void cleanup(void *privdata) {
    RedisMuduoAdapter *adapter = static_cast<RedisMuduoAdapter *>(privdata);
    if (adapter->m_channel) {
      adapter->m_channel->disableAll();
    }
  }

public:
  RedisMuduoAdapter(redisAsyncContext *ac, zephyr::EventLoop *loop)
      : m_ctx(ac), m_loop(loop), m_channel(nullptr) {
    if (ac) {
      setContext(ac);
    }
  }

  ~RedisMuduoAdapter() {
    // 手动释放 channel 内存
    delete m_channel;
  }

  int setContext(redisAsyncContext *ac) {
    m_ctx = ac;
    ac->ev.data = this;
    ac->ev.addRead = addRead;
    ac->ev.delRead = delRead;
    ac->ev.addWrite = addWrite;
    ac->ev.delWrite = delWrite;
    ac->ev.cleanup = cleanup;

    // 延迟初始化 m_channel
    if (!m_channel) {
      m_channel = new zephyr::Channel(m_loop, ac->c.fd);
    }

    return ac->c.fd;
  }

private:
  redisAsyncContext *m_ctx;
  zephyr::EventLoop *m_loop;
  zephyr::Channel *m_channel;
};
#if 1
class RedisAsyncClient : zephyr::noncopyable {
public:
  RedisAsyncClient(zephyr::EventLoop *loop, const std::string &ip, int port)
      : m_ip(ip), m_port(port), m_loop(loop), m_context(nullptr),
        m_adapter(nullptr) {}
  ~RedisAsyncClient() {
    disconnect();
    delete m_adapter;
  }

  // 连接到Redis服务器
  void connect() {
    m_context = redisAsyncConnect(m_ip.c_str(), m_port);
    m_adapter = new RedisMuduoAdapter{m_context, m_loop};
    if (m_context->err) {
      std::cout << "Error: %s\n" << m_context->errstr << std::endl;
      return;
    }

    redisAsyncSetConnectCallback(m_context, connectCallback);
    redisAsyncSetDisconnectCallback(m_context, disconnectCallback);
  }

  // 断开与Redis服务器的连接
  void disconnect() {
    if (m_context) {
      redisAsyncDisconnect(m_context);
      m_context = nullptr;
    }
    m_loop->quit();
  }

  // 执行异步命令
  int command(const std::string &cmd, redisCallbackFn *fn, void *privdata) {
    if (!m_context) {
      std::cout << "Redis Context error" << std::endl;
      return REDIS_ERR;
    }
    return redisAsyncCommand(m_context, fn, privdata, cmd.c_str());
  }

private:
  // 事件回调函数

  // 连接和断开连接的回调函数
  static void connectCallback(const redisAsyncContext *context, int status) {
    if (status != REDIS_OK) {
      LOG_ERROR("Redis connect error: %s", context->errstr);
      return;
    }

    LOG_INFO("Redis connect success");
  }
  static void disconnectCallback(const redisAsyncContext *context, int status) {
    if (status != REDIS_OK) {
      LOG_ERROR("Redis disconnect error: %s", context->errstr);
      return;
    }
    LOG_INFO("Redis disconnect success");

  }

  // 事件处理函数
  void handleRead() {
    if (m_context)
      redisAsyncHandleRead(m_context);
  }
  void handleWrite() {
    if (m_context)
      redisAsyncHandleWrite(m_context);
  }

private:
  std::string m_ip;
  int m_port;
  zephyr::EventLoop *m_loop;
  redisAsyncContext *m_context;
  RedisMuduoAdapter *m_adapter;
};
#endif